/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useCallback, useEffect, useRef } from "react";
import MonacoEditor from "@monaco-editor/react";
import type * as Monaco from "monaco-editor";
import { editor } from "monaco-editor";
import { IFile } from "../../typings";
import Container from "../../container";
import { getFileType } from "../../utils";
import { useEditor } from "../../hooks";
import "./jsx-highlight.less";
import styles from "./index.module.less";

interface Props {
  file: IFile;
  onChange?: (code: string | undefined) => void;
  options?: editor.IStandaloneEditorConstructionOptions;
}

function EditorFiles(props: Props) {
  const { options, file } = props;
  const editorRef = useRef<Monaco.editor.IStandaloneCodeEditor>();
  const jsxSyntaxHighlightRef = useRef<any>({
    highlighter: null,
    dispose: null,
  });
  const { files, currentFileName, setFiles, setCurrentFileName } =
    Container.useContainer();

  const { doOpenEditor, loadJsxSyntaxHighlight, setupEditor } =
    useEditor();

  const onChange = useCallback(
    (code: string | undefined) => {
      if (code) {
        setFiles((draft) => {
          return {
            ...draft,
            [file.name]: {
              ...draft[file.name],
              value: code,
            },
          };
        });
      }
    },
    [file.name, setFiles]
  );

  const handleEditorDidMount = async (
    editor: editor.IStandaloneCodeEditor,
    monaco: any
  ) => {
    if (editor) {
      editorRef.current = editor;
      // ignore save event
      editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
        (editor as any).getAction("editor.action.formatDocument").run();
      });

      monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
        jsx: monaco.languages.typescript.JsxEmit.Preserve,
        target: monaco.languages.typescript.ScriptTarget.ES2020,
        esModuleInterop: true,
      });

      // 初始化自定义文件model
      Object.keys(files).forEach((key) => {
        if (!monaco?.editor?.getModel(monaco.Uri.parse(`file:///${key}`))) {
          monaco?.editor?.createModel(
            files[key].value,
            getFileType(key),
            monaco.Uri.parse(`file:///${key}`)
          );
        }
      });

      // 覆盖原点击变量跳转方法
      (editor as any)._codeEditorService.doOpenEditor = function (
        editor: any,
        input: any
      ) {
        const path = input.resource.path;
        if (!path.startsWith("/node_modules/")) {
          setCurrentFileName(path.replace("/", ""));
          doOpenEditor(editor, input);
        }
      };
      // 加载jsx高亮
      jsxSyntaxHighlightRef.current = loadJsxSyntaxHighlight(editor, monaco);

      // 加载类型定义文件
      setupEditor(editor, monaco, file.value);
    }
  };

  useEffect(() => {
    editorRef.current?.focus();
    jsxSyntaxHighlightRef?.current?.highlighter?.();
  }, [file.name]);

  return (
    <React.Fragment>
      <div
        className={styles.main}
        style={{
          display: file.name === currentFileName ? "block" : "none",
        }}
      >
        <MonacoEditor
          width="100%"
          height="100%"
          theme="vs-dark"
          language={file.type}
          path={file.name}
          onChange={onChange}
          value={file.value}
          onMount={handleEditorDidMount}
          options={{
            ...{
              ...options,
              theme: undefined,
            },
          }}
        />
      </div>
    </React.Fragment>
  );
}

export default EditorFiles;
